<template>
  <div class="validate-input-container pb-3">
    <input
      v-if="inputType === 'input'"
      :class="['form-control', { 'is-invalid': inputRef.error }]"
      @blur="onBlur"
      v-model="inputRef.val"
      v-bind="$attrs"
    />
    <textarea
      v-else
      :class="['form-control', { 'is-invalid': inputRef.error }]"
      @blur="onBlur"
      v-model="inputRef.val"
      v-bind="$attrs"
    />
    <span class="invalid-feedback" v-if="inputRef.error">{{
      inputRef.message
    }}</span>
  </div>
</template>

<script lang="ts">
import {
  computed,
  defineComponent,
  PropType,
  reactive,
  WritableComputedRef,
} from "vue";
import { emitter } from "./ValidateForm.vue";
interface RuleProp {
  type: "required" | "email";
  message?: string;
}
interface inputRefProp {
  val: WritableComputedRef<string>;
  error: boolean;
  message?: string;
}
export type RulesProp = RuleProp[];
export type InputType = "input" | "textarea";
const emailReg =
  /^[a-zA-Z0-9]+((([a-zA-Z0-9]+)?)|(([-_]{1}[a-zA-Z0-9]+)))@[a-zA-Z0-9_-]+(\.[a-zA-Z0-9]+)+$/;

export default defineComponent({
  props: {
    rules: {
      type: Array as PropType<RulesProp>,
      required: false,
    },
    modelValue: String,
    inputType: {
      type: String as PropType<InputType>,
      default: "input",
    },
  },
  inheritAttrs: false,
  setup(props, { emit, attrs }) {
    const inputRef = reactive<inputRefProp>({
      val: computed({
        get: () => props.modelValue || "",
        set(val) {
          emit("update:modelValue", val);
        },
      }),
      error: false,
      message: "",
    });
    const validateInput = () => {
      if (props.rules) {
        const hasError = props.rules.some((rule) => {
          let isError = false;
          inputRef.message = rule.message;
          switch (rule.type) {
            case "required":
              isError = inputRef.val.trim() === "";
              break;
            case "email":
              isError = !inputRef.val.match(emailReg);
              break;
            default:
              break;
          }
          return isError;
        });
        inputRef.error = hasError;
        return !hasError;
      }
      return true;
    };

    emitter.emit("form-item-created", validateInput);
    const onBlur = () => {
      // 由于JavaScript为单线程，同一时间只能执行处理一个事件
      // blur优先级高于click，导致上层submit没有执行，这里延迟执行blur
      setTimeout(() => {
        validateInput();
      }, 300);
    };

    return {
      inputRef,
      validateInput,
      onBlur,
      attrs,
    };
  },
  emits: ["update:modelValue"],
});
</script>

<style lang="less" scoped></style>
